package com.wdb.modules.security.security;

import cn.hutool.core.util.StrUtil;
import com.wdb.modules.security.config.bean.SecurityProperties;
import com.wdb.modules.security.service.OnlineUserService;
import com.wdb.modules.security.service.UserCacheManager;
import com.wdb.modules.security.service.dto.OnlineUserDto;
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;

/**
 * @author: wendaobai@qq.com
 * @date: 2024/1/10 0010 16:14
 */
@Component
public class TokenFilter extends GenericFilterBean {
  private static final Logger log = LoggerFactory.getLogger(TokenFilter.class);
  private final TokenProvider tokenProvider;
  private final SecurityProperties properties;
  private final OnlineUserService onlineUserService;
  private final UserCacheManager userCacheManager;
  /**
   * @param tokenProvider Token
   * @param properties JWT
   * @param onlineUserService 用户在线
   * @param userCacheManager 用户缓存工具
   */
  public TokenFilter(
      TokenProvider tokenProvider,
      SecurityProperties properties,
      OnlineUserService onlineUserService,
      UserCacheManager userCacheManager) {
    this.properties = properties;
    this.onlineUserService = onlineUserService;
    this.tokenProvider = tokenProvider;
    this.userCacheManager = userCacheManager;
  }

  @Override
  public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    System.out.println("doFilter 3333333");
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    String token = resolveToken(httpServletRequest);
    log.info("token:{}", token);
    // 对于 Token 为空的不需要去查 Redis
    if (StrUtil.isNotBlank(token)) {
      OnlineUserDto onlineUserDto = null;
      boolean cleanUserCache = false;
      try {
        String loginKey = tokenProvider.loginKey(token);
        onlineUserDto = onlineUserService.getOne(loginKey);
      } catch (ExpiredJwtException e) {
        log.error(e.getMessage());
        cleanUserCache = true;
      } finally {
        if (cleanUserCache || Objects.isNull(onlineUserDto)) {
          userCacheManager.cleanUserCache(
              String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY)));
        }
      }
      if (onlineUserDto != null && StringUtils.hasText(token)) {
        Authentication authentication = tokenProvider.getAuthentication(token);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // Token 续期
        tokenProvider.checkRenewal(token);
      }
    }
    filterChain.doFilter(servletRequest, servletResponse);
  }
  /**
   * 初步检测Token
   *
   * @param request /
   * @return /
   */
  private String resolveToken(HttpServletRequest request) {
    String bearerToken = request.getHeader(properties.getHeader());
    if (StringUtils.hasText(bearerToken)
        && bearerToken.startsWith(properties.getTokenStartWith())) {
      // 去掉令牌前缀
      return bearerToken.replace(properties.getTokenStartWith(), "");
    } else {
      log.debug("非法Token：{}", bearerToken);
    }
    return null;
  }
}
